<?php

declare(strict_types=1);

namespace App\Middleware\Api;

use App\Model\App\App as AppModel;
use App\Services\Shop\Shop as ShopServices;
use Hyperf\Context\Context;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use App\Services\App\App as AppServices;
use function Hyperf\Translation\__;

/**
 * 验签
 * @author zx
 * @package App\Middleware\Api
 */
class CheckSignMiddleware implements MiddlewareInterface
{
    #[Inject]
    protected ValidatorFactoryInterface $validatorFactory;

    public function __construct(
        protected ContainerInterface $container,
        protected AppServices $appServices,
        protected ShopServices $shopServices
    )
    {
    }

    /**
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     * @throws \Throwable
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $accept = $request->getHeader('accept');
        logs($accept);
        if ($accept && !str_contains(current($accept), 'json') && current($accept) !== '*/*') {
            return failed(__('message.accept', [
                'types' => 'json',
                'type' => current($accept)
            ]));
        }

        $requestInterface = $this->container->get(RequestInterface::class);

        $params = $requestInterface->query();
        $minTimestamp = time()-600;
        $maxTimestamp = time()+600;
        $validator = $this->validatorFactory->make($params, [
            'timestamp' => "required|integer|between:{$minTimestamp},{$maxTimestamp}",
            'app_id' => 'required|alpha_num|max:30',
            'sign' => 'required|alpha_num|size:32'
        ]);

        if ($validator->fails()) {
            return failed($validator->errors()->first());
        }
        /** @var AppModel $appModel */
        $appModel = $this->appServices->where('app_id', $params['app_id'])->firstOrFail();
        $body = $requestInterface->all();
        if (!$appModel->validate($body)) {
            return failed(__('message.sign.failed'));
        }

        $shopModel = $this->shopServices->find($appModel->shop_id);
        Context::set('shopModel', $shopModel);
        Context::set('appModel', $appModel);
        return $handler->handle($request);
    }
}
